#include "../../dwarf/Die.h"
#include "../../dwarf/LexicalBlock.h"
#include "../../dwarf/LocationCursorByAddress.h"
#include "../../dwarf/LocationCursorByDescription.h"
#include "../../dwarf/LocationCursorByRange.h"
#include "../../dwarf/Manager.h"
#include "../../unwind/Frame.h"
#include "SelfDebug.h"

#include <cstdio>

#include <libdwarf/dwarf.h>
#include <stdint.h>

namespace sd {
namespace implementation {

template<typename _T>
static _T bitFieldToSigned(const void *_address, size_t _bitSize, size_t _bitOffset) {
	if ((*(_T *) _address & 1 << (sizeof(_T) * 8 - _bitOffset - 1)) == 0) {
		return (*(_T *) _address >> (sizeof(_T) * 8 - _bitSize - _bitOffset)) & (~_T(0) >> (sizeof(_T) * 8 - _bitSize));
	}
	return (*(_T *) _address >> (sizeof(_T) * 8 - _bitSize - _bitOffset)) | (~_T(0) << _bitSize);
}

template<typename _T>
static _T bitFieldToUnsigned(const void *_address, size_t _bitSize, size_t _bitOffset) {
	return (*(_T *) _address >> (sizeof(_T) * 8 - _bitSize - _bitOffset)) & (~_T(0) >> (sizeof(_T) * 8 - _bitSize));
}

const char *SelfDebug::getTabs(size_t _level) {
	static const char tabs[64] = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t";
	return &tabs[sizeof(tabs) - 1 - _level];
}

SelfDebug::SelfDebug()
		: sd::SelfDebug() {
}

SelfDebug::~SelfDebug() {
}

bool SelfDebug::loadDebugInfo(const char *_file) const {
	if (!dwarf::Manager::getInstance().addDebug(_file)) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	return true;
}

bool SelfDebug::infoLocals() const {
	void *returnPc = unwind::Frame::getPc(1);
	const dwarf::Subprogram *subprogram = dwarf::Manager::getInstance().findSubprogram(returnPc);
	if (subprogram == NULL) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	dwarf::RaiiPointer<Dwarf_Die> die = subprogram->getDie();
	if (die.getPointer() == NULL) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	for (dwarf::RaiiDie childDie = dwarf::Die::getChild(subprogram->getDebug(), die.getPointer()); childDie.getPointer() != NULL; childDie.next()) {
		Dwarf_Half tag;
		int rtn = dwarf::Die::getTag(childDie.getPointer(), tag);
		if (rtn == DW_DLV_ERROR) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		else if (rtn == DW_DLV_NO_ENTRY) {
			continue;
		}
		if (tag != DW_TAG_lexical_block) {
			continue;
		}
		if (!infoLocalsInLexicalBlock(subprogram->getDebug(), childDie.getPointer(), returnPc, unwind::Frame::getAddress(1))) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		return true;
	}
	return true;
}

bool SelfDebug::infoLocalsInLexicalBlock(Dwarf_Debug _debug, Dwarf_Die _die, const void *_framePc, const void *_frameAddress, bool *_finish) const {
	if (_finish != NULL) {
		*_finish = false;
	}
	for (dwarf::RaiiDie childDie = dwarf::Die::getChild(_debug, _die); childDie.getPointer() != NULL; childDie.next()) {
		Dwarf_Half tag;
		int rtn = dwarf::Die::getTag(childDie.getPointer(), tag);
		if (rtn == DW_DLV_ERROR) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		else if (rtn == DW_DLV_NO_ENTRY) {
			continue;
		}
		if (tag == DW_TAG_lexical_block) {
			if (!dwarf::LexicalBlock::contains(_debug, childDie.getPointer(), _framePc)) {
				continue;
			}
			bool finish;
			if (!infoLocalsInLexicalBlock(_debug, childDie.getPointer(), _framePc, _frameAddress, &finish)) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			if (finish) {
				if (_finish != NULL) {
					*_finish = true;
				}
				return true;
			}
		}
		else if (tag == DW_TAG_inlined_subroutine) {
			if (!dwarf::LexicalBlock::contains(_debug, childDie.getPointer(), _framePc)) {
				continue;
			}
			if (!infoLocalsInInlinedSubroutine(_debug, childDie.getPointer(), _framePc, _frameAddress)) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			if (_finish != NULL) {
				*_finish = true;
			}
			return true;
		}
	}
	for (dwarf::RaiiDie childDie = dwarf::Die::getChild(_debug, _die); childDie.getPointer() != NULL; childDie.next()) {
		Dwarf_Half tag;
		int rtn = dwarf::Die::getTag(childDie.getPointer(), tag);
		if (rtn == DW_DLV_ERROR) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		else if (rtn == DW_DLV_NO_ENTRY) {
			continue;
		}
		if (tag != DW_TAG_variable) {
			continue;
		}
		if (!printLocal(_debug, childDie.getPointer(), _frameAddress, 0)) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
	}
	return true;
}

bool SelfDebug::infoLocalsInInlinedSubroutine(Dwarf_Debug _debug, Dwarf_Die _die, const void *_framePc, const void *_frameAddress) const {
	for (dwarf::RaiiDie childDie = dwarf::Die::getChild(_debug, _die); childDie.getPointer() != NULL; childDie.next()) {
		Dwarf_Half tag;
		int rtn = dwarf::Die::getTag(childDie.getPointer(), tag);
		if (rtn == DW_DLV_ERROR) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		else if (rtn == DW_DLV_NO_ENTRY) {
			continue;
		}
		if (tag != DW_TAG_lexical_block) {
			continue;
		}
		if (!dwarf::LexicalBlock::contains(_debug, childDie.getPointer(), _framePc)) {
			continue;
		}
		if (!infoLocalsInLexicalBlock(_debug, childDie.getPointer(), _framePc, _frameAddress)) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		return true;
	}
	return true;
}

bool SelfDebug::print(Dwarf_Debug _debug, Dwarf_Die _typeDie, dwarf::LocationCursor &_locationCursor, size_t _level) const {
	Dwarf_Half typeTag;
	int rtn = dwarf::Die::getTag(_typeDie, typeTag);
	if (rtn == DW_DLV_ERROR) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	else if (rtn == DW_DLV_NO_ENTRY) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	switch (typeTag) {
		case DW_TAG_array_type: {
			dwarf::RaiiPointer<Dwarf_Die> elementTypeDie(_debug);
			rtn = dwarf::Die::getType(_debug, _typeDie, elementTypeDie);
			if (rtn == DW_DLV_ERROR) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			else if (rtn == DW_DLV_NO_ENTRY) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			Dwarf_Error error;
			Dwarf_Unsigned elementTypeByteSize;
			rtn = dwarf_bytesize(elementTypeDie.getPointer(), &elementTypeByteSize, &error);
			if (rtn == DW_DLV_ERROR) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			else if (rtn == DW_DLV_NO_ENTRY) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			Dwarf_Half elementTypeTag;
			rtn = dwarf::Die::getTag(elementTypeDie.getPointer(), elementTypeTag);
			if (rtn == DW_DLV_ERROR) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			else if (rtn == DW_DLV_NO_ENTRY) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			bool elementTypeIsChar = false;
			if (elementTypeTag == DW_TAG_base_type) {
				Dwarf_Unsigned elementTypeEncoding;
				rtn = dwarf::Die::getEncoding(_debug, elementTypeDie.getPointer(), elementTypeEncoding);
				if (rtn == DW_DLV_ERROR) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				else if (rtn == DW_DLV_NO_ENTRY) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				elementTypeIsChar = (elementTypeEncoding == DW_ATE_signed && elementTypeByteSize == sizeof(int8_t))
									|| elementTypeEncoding == DW_ATE_signed_char
									|| (elementTypeEncoding == DW_ATE_unsigned && elementTypeByteSize == sizeof(uint8_t))
									|| elementTypeEncoding == DW_ATE_unsigned_char;
			}
			size_t dimension = 0;
			size_t sizes[64];
			for (dwarf::RaiiDie childDie = dwarf::Die::getChild(_debug, _typeDie); childDie.getPointer() != NULL; childDie.next()) {
				Dwarf_Unsigned upperBound;
				rtn = dwarf::Die::getUpperBound(_debug, childDie.getPointer(), upperBound);
				if (rtn == DW_DLV_ERROR) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				else if (rtn == DW_DLV_NO_ENTRY) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				sizes[dimension] = upperBound + 1;
				++dimension;
			}
			if (dimension == 0) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			else if (dimension == 1) {
				if (elementTypeIsChar) {
					bool first = true;
					for (size_t i = 0; i < sizes[0]; ++i) {
						const dwarf::Location &location = _locationCursor.fetch(sizeof(unsigned char));
						switch (location.getType()) {
							case dwarf::Location::TYPE_ADDRESS: {
								if (location.getSize() != sizeof(unsigned char)) {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
								if (first && i == 0) {
									printf("\"");
									first = false;
								}
								else if (first && i != 0) {
									printf(" + \"");
									first = false;
								}
								unsigned char &c = *(unsigned char *) location.getAddress();
								if (c >= ' ' && c <= '~') {
									printf("%c", c);
								}
								else {
									printf("\\%02x", c);
								}
								break;
							}
							case dwarf::Location::TYPE_OPTIMIZED_OUT: {
								if (!first) {
									printf("\" + ");
									first = true;
								}
								else if (i != 0) {
									printf(" + ");
								}
								printf("$.oo");
								break;
							}
							default: {
								fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
								return false;
							}
						}
					}
					if (!first) {
						printf("\"");
					}
				}
				else {
					printf("[");
					for (size_t i = 0; i < sizes[0]; ++i) {
						if (i != 0) {
							printf(", ");
						}
						if (!print(_debug, elementTypeDie.getPointer(), _locationCursor, _level + 1)) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
					}
					printf("]");
				}
			}
			else {
				for (size_t i = dimension - 1; i > 0; --i) {
					sizes[i - 1] *= sizes[i];
				}
				if (flattenMultidimensionalArray_) {
					printf("{\n");
					for (size_t i = 0; i < sizes[0];) {
						printf("%s\"", getTabs(_level + 1));
						for (size_t j = 1; j <= dimension - 1; ++j) {
							printf("[%zu]", i % sizes[j - 1] / sizes[j]);
						}
						printf("\": ");
						if (elementTypeIsChar) {
							bool first = true;
							for (size_t j = 0; j < sizes[dimension - 1]; ++j) {
								const dwarf::Location &location = _locationCursor.fetch(sizeof(unsigned char));
								switch (location.getType()) {
									case dwarf::Location::TYPE_ADDRESS: {
										if (location.getSize() != sizeof(unsigned char)) {
											fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
											return false;
										}
										if (first && j == 0) {
											printf("\"");
											first = false;
										}
										else if (first && j != 0) {
											printf(" + \"");
											first = false;
										}
										unsigned char &c = *(unsigned char *) location.getAddress();
										if (c >= ' ' && c <= '~') {
											printf("%c", c);
										}
										else {
											printf("\\%02x", c);
										}
										break;
									}
									case dwarf::Location::TYPE_OPTIMIZED_OUT: {
										if (!first) {
											printf("\" + ");
											first = true;
										}
										else if (j != 0) {
											printf(" + ");
										}
										printf("$.oo");
										break;
									}
									default: {
										fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
										return false;
									}
								}
								++i;
							}
							if (!first) {
								printf("\"");
							}
							printf("\n");
						}
						else {
							printf("[");
							for (size_t j = 0; j < sizes[dimension - 1]; ++j) {
								if (j != 0) {
									printf(", ");
								}
								if (!print(_debug, elementTypeDie.getPointer(), _locationCursor, _level + 1)) {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
								++i;
							}
							printf("]\n");
						}
					}
					printf("%s}", getTabs(_level));
				}
				else {
					for (size_t i = dimension - 1; i > 0; --i) {
						printf("[");
					}
					for (size_t i = 0; i < sizes[0];) {
						if (elementTypeIsChar) {
							bool first = true;
							for (size_t j = 0; j < sizes[dimension - 1]; ++j) {
								const dwarf::Location &location = _locationCursor.fetch(sizeof(unsigned char));
								switch (location.getType()) {
									case dwarf::Location::TYPE_ADDRESS: {
										if (location.getSize() != sizeof(unsigned char)) {
											fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
											return false;
										}
										if (first && j == 0) {
											printf("\"");
											first = false;
										}
										else if (first && j != 0) {
											printf(" + \"");
											first = false;
										}
										unsigned char &c = *(unsigned char *) location.getAddress();
										if (c >= ' ' && c <= '~') {
											printf("%c", c);
										}
										else {
											printf("\\%02x", c);
										}
										break;
									}
									case dwarf::Location::TYPE_OPTIMIZED_OUT: {
										if (!first) {
											printf("\" + ");
											first = true;
										}
										else if (j != 0) {
											printf(" + ");
										}
										printf("$.oo");
										break;
									}
									default: {
										fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
										return false;
									}
								}
								++i;
							}
							if (!first) {
								printf("\"");
							}
						}
						else {
							printf("[");
							for (size_t j = 0; j < sizes[dimension - 1]; ++j) {
								if (j != 0) {
									printf(", ");
								}
								if (!print(_debug, elementTypeDie.getPointer(), _locationCursor, _level + 1)) {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
								++i;
							}
							printf("]");
						}
						if (i < sizes[0] && dimension > 1) {
							size_t j = dimension - 2;
							for (; j > 0; --j) {
								if (i % sizes[j] != 0) {
									break;
								}
								printf("]");
							}
							printf(", ");
							for (; j < dimension - 2; ++j) {
								printf("[");
							}
						}
					}
					for (size_t i = dimension - 1; i > 0; --i) {
						printf("]");
					}
				}
			}
			return true;
		}
		case DW_TAG_class_type: {
			Dwarf_Error error;
			Dwarf_Unsigned typeByteSize;
			rtn = dwarf_bytesize(_typeDie, &typeByteSize, &error);
			if (rtn == DW_DLV_ERROR) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			else if (rtn == DW_DLV_NO_ENTRY) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			const dwarf::Location &location = _locationCursor.fetch(typeByteSize);
			switch (location.getType()) {
				case dwarf::Location::TYPE_ADDRESS: {
					if (location.getSize() != typeByteSize) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					printf("{\n");
					for (dwarf::RaiiDie childDie = dwarf::Die::getChild(_debug, _typeDie); childDie.getPointer() != NULL; childDie.next()) {
						Dwarf_Half childTag;
						rtn = dwarf::Die::getTag(childDie.getPointer(), childTag);
						if (rtn == DW_DLV_ERROR) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						else if (rtn == DW_DLV_NO_ENTRY) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						switch (childTag) {
							case DW_TAG_inheritance: {
								if (!printInheritance(_debug, childDie.getPointer(), location.getAddress(), _level + 1)) {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
								break;
							}
							case DW_TAG_member: {
								dwarf::RaiiPointer<Dwarf_Attribute> attribute(_debug);
								rtn = dwarf::Die::getAttribute(childDie.getPointer(), DW_AT_external, attribute);
								if (rtn == DW_DLV_ERROR) {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
								else if (rtn == DW_DLV_OK) {
									bool external;
									rtn = dwarf::Die::getExternal(attribute.getPointer(), external);
									if (rtn == DW_DLV_ERROR) {
										fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
										return false;
									}
									else if (rtn == DW_DLV_NO_ENTRY) {
										fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
										return false;
									}
									if (external) {
										continue;
									}
								}
								if (!printMember(_debug, childDie.getPointer(), location.getAddress(), _level + 1)) {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
								break;
							}
							default: {
								break;
							}
						}
					}
					printf("%s}", getTabs(_level));
					return true;
				}
				case dwarf::Location::TYPE_OPTIMIZED_OUT: {
					printf("$.oo");
					return true;
				}
				default: {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
			}
		}
		case DW_TAG_enumeration_type: {
			Dwarf_Error error;
			Dwarf_Unsigned typeByteSize;
			rtn = dwarf_bytesize(_typeDie, &typeByteSize, &error);
			if (rtn == DW_DLV_ERROR) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			else if (rtn == DW_DLV_NO_ENTRY) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			const dwarf::Location &location = _locationCursor.fetch(typeByteSize);
			switch (location.getType()) {
				case dwarf::Location::TYPE_ADDRESS: {
					Dwarf_Signed value;
					switch (typeByteSize) {
						case sizeof(int8_t): {
							switch (location.getSize()) {
								case sizeof(int8_t): {
									value = *(int8_t *) location.getAddress();
									break;
								}
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
							break;
						}
						case sizeof(int16_t): {
							switch (location.getSize()) {
								case sizeof(int8_t): {
									value = *(int8_t *) location.getAddress();
									break;
								}
								case sizeof(int16_t): {
									value = *(int16_t *) location.getAddress();
									break;
								}
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
							break;
						}
						case sizeof(int32_t): {
							switch (location.getSize()) {
								case sizeof(int8_t): {
									value = *(int8_t *) location.getAddress();
									break;
								}
								case sizeof(int16_t): {
									value = *(int16_t *) location.getAddress();
									break;
								}
								case sizeof(int32_t): {
									value = *(int32_t *) location.getAddress();
									break;
								}
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
							break;
						}
						case sizeof(int64_t): {
							switch (location.getSize()) {
								case sizeof(int8_t): {
									value = *(int8_t *) location.getAddress();
									break;
								}
								case sizeof(int16_t): {
									value = *(int16_t *) location.getAddress();
									break;
								}
								case sizeof(int32_t): {
									value = *(int32_t *) location.getAddress();
									break;
								}
								case sizeof(int64_t): {
									value = *(int64_t *) location.getAddress();
									break;
								}
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
							break;
						}
						default: {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
					}
					for (dwarf::RaiiDie childDie = dwarf::Die::getChild(_debug, _typeDie); childDie.getPointer() != NULL; childDie.next()) {
						dwarf::RaiiPointer<Dwarf_Attribute> attribute(_debug);
						rtn = dwarf::Die::getAttribute(childDie.getPointer(), DW_AT_const_value, attribute);
						if (rtn == DW_DLV_ERROR) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						else if (rtn == DW_DLV_NO_ENTRY) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						Dwarf_Half attributeFormat;
						rtn = dwarf_whatform(attribute.getPointer(), &attributeFormat, &error);
						if (rtn == DW_DLV_ERROR) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						else if (rtn == DW_DLV_NO_ENTRY) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						if (attributeFormat != DW_FORM_sdata) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						Dwarf_Signed s;
						rtn = dwarf_formsdata(attribute.getPointer(), &s, &error);
						if (rtn == DW_DLV_ERROR) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						else if (rtn == DW_DLV_NO_ENTRY) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						if (value != s) {
							continue;
						}
						dwarf::RaiiPointer<char *> name(_debug);
						rtn = dwarf::Die::getName(childDie.getPointer(), name);
						if (rtn == DW_DLV_ERROR) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						else if (rtn == DW_DLV_NO_ENTRY) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						printf("%s", name.getPointer());
						return true;
					}
					printf("%lli", value);
					return true;
				}
				case dwarf::Location::TYPE_OPTIMIZED_OUT: {
					printf("$.oo");
					return true;
				}
				default: {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
			}
		}
		case DW_TAG_pointer_type: {
			const dwarf::Location &location = _locationCursor.fetch(sizeof(void *));
			switch (location.getType()) {
				case dwarf::Location::TYPE_ADDRESS: {
					intptr_t value;
					switch (location.getSize()) {
						case sizeof(int8_t): {
							value = *(int8_t *) location.getAddress();
							break;
						}
						case sizeof(int16_t): {
							value = *(int16_t *) location.getAddress();
							break;
						}
						case sizeof(int32_t): {
							value = *(int32_t *) location.getAddress();
							break;
						}
#if (defined __x86_64)
						case sizeof(int64_t): {
							value = *(int64_t *) location.getAddress();
							break;
						}
#endif
						default: {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
					}
					printf("%p", (void *) value);
					return true;
				}
				case dwarf::Location::TYPE_SYNTHETIC_POINTER: {
					printf("$.sp");
					return true;
				}
				case dwarf::Location::TYPE_OPTIMIZED_OUT: {
					printf("$.oo");
					return true;
				}
				default: {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
			}
		}
		case DW_TAG_reference_type: {
			const dwarf::Location &location = _locationCursor.fetch(sizeof(void *));
			switch (location.getType()) {
				case dwarf::Location::TYPE_ADDRESS: {
					intptr_t value;
					switch (location.getSize()) {
						case sizeof(int8_t): {
							value = *(int8_t *) location.getAddress();
							break;
						}
						case sizeof(int16_t): {
							value = *(int16_t *) location.getAddress();
							break;
						}
						case sizeof(int32_t): {
							value = *(int32_t *) location.getAddress();
							break;
						}
#if (defined __x86_64)
						case sizeof(int64_t): {
							value = *(int64_t *) location.getAddress();
							break;
						}
#endif
						default: {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
					}
					printf("%p", (void *) value);
					return true;
				}
				case dwarf::Location::TYPE_SYNTHETIC_POINTER: {
					printf("$.sp");
					return true;
				}
				case dwarf::Location::TYPE_OPTIMIZED_OUT: {
					printf("$.oo");
					return true;
				}
				default: {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
			}
		}
		case DW_TAG_structure_type: {
			Dwarf_Error error;
			Dwarf_Unsigned typeByteSize;
			rtn = dwarf_bytesize(_typeDie, &typeByteSize, &error);
			if (rtn == DW_DLV_ERROR) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			else if (rtn == DW_DLV_NO_ENTRY) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			const dwarf::Location &location = _locationCursor.fetch(typeByteSize);
			switch (location.getType()) {
				case dwarf::Location::TYPE_ADDRESS: {
					if (location.getSize() != typeByteSize) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					printf("{\n");
					for (dwarf::RaiiDie childDie = dwarf::Die::getChild(_debug, _typeDie); childDie.getPointer() != NULL; childDie.next()) {
						Dwarf_Half childTag;
						rtn = dwarf::Die::getTag(childDie.getPointer(), childTag);
						if (rtn == DW_DLV_ERROR) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						else if (rtn == DW_DLV_NO_ENTRY) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						switch (childTag) {
							case DW_TAG_inheritance: {
								if (!printInheritance(_debug, childDie.getPointer(), location.getAddress(), _level + 1)) {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
								break;
							}
							case DW_TAG_member: {
								dwarf::RaiiPointer<Dwarf_Attribute> attribute(_debug);
								rtn = dwarf::Die::getAttribute(childDie.getPointer(), DW_AT_external, attribute);
								if (rtn == DW_DLV_ERROR) {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
								else if (rtn == DW_DLV_OK) {
									bool external;
									rtn = dwarf::Die::getExternal(attribute.getPointer(), external);
									if (rtn == DW_DLV_ERROR) {
										fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
										return false;
									}
									else if (rtn == DW_DLV_NO_ENTRY) {
										fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
										return false;
									}
									if (external) {
										continue;
									}
								}
								if (!printMember(_debug, childDie.getPointer(), location.getAddress(), _level + 1)) {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
								break;
							}
							default: {
								break;
							}
						}
					}
					printf("%s}", getTabs(_level));
					return true;
				}
				case dwarf::Location::TYPE_OPTIMIZED_OUT: {
					printf("$.oo");
					return true;
				}
				default: {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
			}
		}
		case DW_TAG_typedef: {
			dwarf::RaiiPointer<Dwarf_Die> type(_debug);
			rtn = dwarf::Die::getType(_debug, _typeDie, type);
			if (rtn == DW_DLV_ERROR) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			else if (rtn == DW_DLV_NO_ENTRY) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			if (!print(_debug, type.getPointer(), _locationCursor, _level)) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			return true;
		}
		case DW_TAG_union_type: {
			Dwarf_Error error;
			Dwarf_Unsigned typeByteSize;
			rtn = dwarf_bytesize(_typeDie, &typeByteSize, &error);
			if (rtn == DW_DLV_ERROR) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			else if (rtn == DW_DLV_NO_ENTRY) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			const dwarf::Location &location = _locationCursor.fetch(typeByteSize);
			switch (location.getType()) {
				case dwarf::Location::TYPE_ADDRESS: {
					if (location.getSize() > typeByteSize) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					printf("{\n");
					for (dwarf::RaiiDie childDie = dwarf::Die::getChild(_debug, _typeDie); childDie.getPointer() != NULL; childDie.next()) {
						Dwarf_Half childTag;
						rtn = dwarf::Die::getTag(childDie.getPointer(), childTag);
						if (rtn == DW_DLV_ERROR) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						else if (rtn == DW_DLV_NO_ENTRY) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						if (childTag != DW_TAG_member) {
							continue;
						}
						dwarf::RaiiPointer<char *> name(_debug);
						rtn = dwarf::Die::getName(childDie.getPointer(), name);
						if (rtn == DW_DLV_ERROR) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						else if (rtn == DW_DLV_NO_ENTRY) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						printf("%s\t%s: ", getTabs(_level), name.getPointer());
						dwarf::RaiiPointer<Dwarf_Die> type(_debug);
						rtn = dwarf::Die::getType(_debug, childDie.getPointer(), type);
						if (rtn == DW_DLV_ERROR) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						else if (rtn == DW_DLV_NO_ENTRY) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						dwarf::LocationCursorByRange locationCursor(location.getAddress(), location.getSize());
						if (!print(_debug, type.getPointer(), locationCursor, _level + 2)) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						printf("\n");
					}
					printf("%s}", getTabs(_level));
					return true;
				}
				case dwarf::Location::TYPE_OPTIMIZED_OUT: {
					printf("$.oo");
					return true;
				}
				default: {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
			}
		}
		case DW_TAG_base_type: {
			Dwarf_Unsigned typeEncoding;
			rtn = dwarf::Die::getEncoding(_debug, _typeDie, typeEncoding);
			if (rtn == DW_DLV_ERROR) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			else if (rtn == DW_DLV_NO_ENTRY) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			switch (typeEncoding) {
				case DW_ATE_address: {
					const dwarf::Location &location = _locationCursor.fetch(sizeof(void *));
					switch (location.getType()) {
						case dwarf::Location::TYPE_ADDRESS: {
							intptr_t value;
							switch (location.getSize()) {
								case sizeof(int8_t): {
									value = *(int8_t *) location.getAddress();
									break;
								}
								case sizeof(int16_t): {
									value = *(int16_t *) location.getAddress();
									break;
								}
								case sizeof(int32_t): {
									value = *(int32_t *) location.getAddress();
									break;
								}
#if (defined __x86_64)
								case sizeof(int64_t): {
									value = *(int64_t *) location.getAddress();
									break;
								}
#endif
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
							printf("%p", (void *) value);
							return true;
						}
						case dwarf::Location::TYPE_SYNTHETIC_POINTER: {
							printf("$.sp");
							return true;
						}
						case dwarf::Location::TYPE_OPTIMIZED_OUT: {
							printf("$.oo");
							return true;
						}
						default: {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
					}
				}
				case DW_ATE_boolean: {
					const dwarf::Location &location = _locationCursor.fetch(sizeof(bool));
					switch (location.getType()) {
						case dwarf::Location::TYPE_ADDRESS: {
							if (location.getSize() != sizeof(bool)) {
								fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
								return false;
							}
							printf("%d", *(bool *) location.getAddress());
							return true;
						}
						case dwarf::Location::TYPE_OPTIMIZED_OUT: {
							printf("$.oo");
							return true;
						}
						default: {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
					}
				}
				case DW_ATE_float: {
					Dwarf_Error error;
					Dwarf_Unsigned typeByteSize;
					rtn = dwarf_bytesize(_typeDie, &typeByteSize, &error);
					if (rtn == DW_DLV_ERROR) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					else if (rtn == DW_DLV_NO_ENTRY) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					switch (typeByteSize) {
						case sizeof(float): {
							const dwarf::Location &location = _locationCursor.fetch(sizeof(float));
							switch (location.getType()) {
								case dwarf::Location::TYPE_ADDRESS: {
									if (location.getSize() != sizeof(float)) {
										fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
										return false;
									}
									printf("%g", *(float *) location.getAddress());
									return true;
								}
								case dwarf::Location::TYPE_OPTIMIZED_OUT: {
									printf("$.oo");
									return true;
								}
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
						}
						case sizeof(double): {
							const dwarf::Location &location = _locationCursor.fetch(sizeof(double));
							switch (location.getType()) {
								case dwarf::Location::TYPE_ADDRESS: {
									if (location.getSize() != sizeof(double)) {
										fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
										return false;
									}
									printf("%g", *(double *) location.getAddress());
									return true;
								}
								case dwarf::Location::TYPE_OPTIMIZED_OUT: {
									printf("$.oo");
									return true;
								}
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
						}
						default: {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
					}
				}
				case DW_ATE_signed: {
					Dwarf_Error error;
					Dwarf_Unsigned typeByteSize;
					rtn = dwarf_bytesize(_typeDie, &typeByteSize, &error);
					if (rtn == DW_DLV_ERROR) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					else if (rtn == DW_DLV_NO_ENTRY) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					switch (typeByteSize) {
						case sizeof(int8_t): {
							const dwarf::Location &location = _locationCursor.fetch(sizeof(unsigned char));
							switch (location.getType()) {
								case dwarf::Location::TYPE_ADDRESS: {
									if (location.getSize() != sizeof(unsigned char)) {
										fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
										return false;
									}
									unsigned char &c = *(unsigned char *) location.getAddress();
									if (c >= ' ' && c <= '~') {
										printf("'%c'", c);
									}
									else {
										printf("'\\%02x'", c);
									}
									return true;
								}
								case dwarf::Location::TYPE_OPTIMIZED_OUT: {
									printf("$.oo");
									return true;
								}
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
						}
						case sizeof(int16_t): {
							int16_t value;
							const dwarf::Location &location = _locationCursor.fetch(sizeof(int16_t));
							switch (location.getType()) {
								case dwarf::Location::TYPE_ADDRESS: {
									switch (location.getSize()) {
										case sizeof(int8_t): {
											value = *(int8_t *) location.getAddress();
											break;
										}
										case sizeof(int16_t): {
											value = *(int16_t *) location.getAddress();
											break;
										}
										default: {
											fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
											return false;
										}
									}
									printf("%hi", value);
									return true;
								}
								case dwarf::Location::TYPE_OPTIMIZED_OUT: {
									printf("$.oo");
									return true;
								}
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
						}
						case sizeof(int32_t): {
							int32_t value;
							const dwarf::Location &location = _locationCursor.fetch(sizeof(int32_t));
							switch (location.getType()) {
								case dwarf::Location::TYPE_ADDRESS: {
									switch (location.getSize()) {
										case sizeof(int8_t): {
											value = *(int8_t *) location.getAddress();
											break;
										}
										case sizeof(int16_t): {
											value = *(int16_t *) location.getAddress();
											break;
										}
										case sizeof(int32_t): {
											value = *(int32_t *) location.getAddress();
											break;
										}
										default: {
											fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
											return false;
										}
									}
									printf("%i", value);
									return true;
								}
								case dwarf::Location::TYPE_OPTIMIZED_OUT: {
									printf("$.oo");
									return true;
								}
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
						}
						case sizeof(int64_t): {
							int64_t value;
							const dwarf::Location &location = _locationCursor.fetch(sizeof(int64_t));
							switch (location.getType()) {
								case dwarf::Location::TYPE_ADDRESS: {
									switch (location.getSize()) {
										case sizeof(int8_t): {
											value = *(int8_t *) location.getAddress();
											break;
										}
										case sizeof(int16_t): {
											value = *(int16_t *) location.getAddress();
											break;
										}
										case sizeof(int32_t): {
											value = *(int32_t *) location.getAddress();
											break;
										}
										case sizeof(int64_t): {
											value = *(int64_t *) location.getAddress();
											break;
										}
										default: {
											fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
											return false;
										}
									}
									printf("%li", value);
									return true;
								}
								case dwarf::Location::TYPE_OPTIMIZED_OUT: {
									printf("$.oo");
									return true;
								}
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
						}
						default: {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
					}
				}
				case DW_ATE_signed_char: {
					const dwarf::Location &location = _locationCursor.fetch(sizeof(unsigned char));
					switch (location.getType()) {
						case dwarf::Location::TYPE_ADDRESS: {
							if (location.getSize() != sizeof(unsigned char)) {
								fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
								return false;
							}
							unsigned char &c = *(unsigned char *) location.getAddress();
							if (c >= ' ' && c <= '~') {
								printf("'%c'", c);
							}
							else {
								printf("'\\%02x'", c);
							}
							return true;
						}
						case dwarf::Location::TYPE_OPTIMIZED_OUT: {
							printf("$.oo");
							return true;
						}
						default: {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
					}
				}
				case DW_ATE_unsigned: {
					Dwarf_Error error;
					Dwarf_Unsigned typeByteSize;
					rtn = dwarf_bytesize(_typeDie, &typeByteSize, &error);
					if (rtn == DW_DLV_ERROR) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					else if (rtn == DW_DLV_NO_ENTRY) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					switch (typeByteSize) {
						case sizeof(uint8_t): {
							const dwarf::Location &location = _locationCursor.fetch(sizeof(unsigned char));
							switch (location.getType()) {
								case dwarf::Location::TYPE_ADDRESS: {
									if (location.getSize() != sizeof(unsigned char)) {
										fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
										return false;
									}
									unsigned char &c = *(unsigned char *) location.getAddress();
									if (c >= ' ' && c <= '~') {
										printf("'%c'", c);
									}
									else {
										printf("'\\%02x'", c);
									}
									return true;
								}
								case dwarf::Location::TYPE_OPTIMIZED_OUT: {
									printf("$.oo");
									return true;
								}
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
						}
						case sizeof(uint16_t): {
							uint16_t value;
							const dwarf::Location &location = _locationCursor.fetch(sizeof(uint16_t));
							switch (location.getType()) {
								case dwarf::Location::TYPE_ADDRESS: {
									switch (location.getSize()) {
										case sizeof(uint8_t): {
											value = *(uint8_t *) location.getAddress();
											break;
										}
										case sizeof(uint16_t): {
											value = *(uint16_t *) location.getAddress();
											break;
										}
										default: {
											fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
											return false;
										}
									}
									printf("%hu", value);
									return true;
								}
								case dwarf::Location::TYPE_OPTIMIZED_OUT: {
									printf("$.oo");
									return true;
								}
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
						}
						case sizeof(uint32_t): {
							uint32_t value;
							const dwarf::Location &location = _locationCursor.fetch(sizeof(uint32_t));
							switch (location.getType()) {
								case dwarf::Location::TYPE_ADDRESS: {
									switch (location.getSize()) {
										case sizeof(uint8_t): {
											value = *(uint8_t *) location.getAddress();
											break;
										}
										case sizeof(uint16_t): {
											value = *(uint16_t *) location.getAddress();
											break;
										}
										case sizeof(uint32_t): {
											value = *(uint32_t *) location.getAddress();
											break;
										}
										default: {
											fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
											return false;
										}
									}
									printf("%u", value);
									return true;
								}
								case dwarf::Location::TYPE_OPTIMIZED_OUT: {
									printf("$.oo");
									return true;
								}
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
						}
						case sizeof(uint64_t): {
							uint64_t value;
							const dwarf::Location &location = _locationCursor.fetch(sizeof(uint64_t));
							switch (location.getType()) {
								case dwarf::Location::TYPE_ADDRESS: {
									switch (location.getSize()) {
										case sizeof(uint8_t): {
											value = *(uint8_t *) location.getAddress();
											break;
										}
										case sizeof(uint16_t): {
											value = *(uint16_t *) location.getAddress();
											break;
										}
										case sizeof(uint32_t): {
											value = *(uint32_t *) location.getAddress();
											break;
										}
										case sizeof(uint64_t): {
											value = *(uint64_t *) location.getAddress();
											break;
										}
										default: {
											fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
											return false;
										}
									}
									printf("%lu", value);
									return true;
								}
								case dwarf::Location::TYPE_OPTIMIZED_OUT: {
									printf("$.oo");
									return true;
								}
								default: {
									fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
									return false;
								}
							}
						}
						default: {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
					}
				}
				case DW_ATE_unsigned_char: {
					const dwarf::Location &location = _locationCursor.fetch(sizeof(unsigned char));
					switch (location.getType()) {
						case dwarf::Location::TYPE_ADDRESS: {
							if (location.getSize() != sizeof(unsigned char)) {
								fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
								return false;
							}
							unsigned char &c = *(unsigned char *) location.getAddress();
							if (c >= ' ' && c <= '~') {
								printf("'%c'", c);
							}
							else {
								printf("'\\%02x'", c);
							}
							return true;
						}
						case dwarf::Location::TYPE_OPTIMIZED_OUT: {
							printf("$.oo");
							return true;
						}
						default: {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
					}
				}
				default: {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
			}
		}
		case DW_TAG_const_type: {
			dwarf::RaiiPointer<Dwarf_Die> contentTypeDie(_debug);
			rtn = dwarf::Die::getType(_debug, _typeDie, contentTypeDie);
			if (rtn == DW_DLV_ERROR) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			else if (rtn == DW_DLV_NO_ENTRY) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			if (!print(_debug, contentTypeDie.getPointer(), _locationCursor, _level)) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			return true;
		}
		default: {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
	}
}

bool SelfDebug::printArgument(Dwarf_Debug _debug, Dwarf_Die _argument, const void *_frame, size_t _level) const {
	return true;
}

bool SelfDebug::printLocal(Dwarf_Debug _debug, Dwarf_Die _local, const void *_frame, size_t _level) const {
	Dwarf_Die local = _local;
	dwarf::RaiiDie die(_debug);
	Dwarf_Off abstractOrigin;
	int rtn = dwarf::Die::getAbstractOrigin(_debug, _local, abstractOrigin);
	if (rtn == DW_DLV_ERROR) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	else if (rtn == DW_DLV_OK) {
		Dwarf_Error error;
		rtn = dwarf_offdie(_debug, abstractOrigin, &die.getPointer(), &error);
		if (rtn == DW_DLV_ERROR) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		else if (rtn == DW_DLV_NO_ENTRY) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		local = die.getPointer();
	}
	dwarf::RaiiPointer<char *> name(_debug);
	rtn = dwarf::Die::getName(local, name);
	if (rtn == DW_DLV_ERROR) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	else if (rtn == DW_DLV_NO_ENTRY) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	printf("%s%s: ", getTabs(_level), name.getPointer());
	dwarf::RaiiPointer<Dwarf_Die> type(_debug);
	rtn = dwarf::Die::getType(_debug, local, type);
	if (rtn == DW_DLV_ERROR) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	else if (rtn == DW_DLV_NO_ENTRY) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	dwarf::RaiiPointer<Dwarf_Attribute> attribute(_debug);
	rtn = dwarf::Die::getAttribute(_local, DW_AT_location, attribute);
	if (rtn == DW_DLV_ERROR) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	else if (rtn == DW_DLV_OK) {
		dwarf::RaiiPointer<Dwarf_Locdesc *> locationDescription(_debug);
		rtn = dwarf::Die::getLocationDescription(_debug, _local, attribute.getPointer(), locationDescription);
		if (rtn == DW_DLV_ERROR) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		else if (rtn == DW_DLV_NO_ENTRY) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		dwarf::LocationCursorByDescription locationCursor(_frame, _debug, locationDescription.getPointer());
		if (!print(_debug, type.getPointer(), locationCursor, _level)) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		printf("\n");
		return true;
	}
	rtn = dwarf::Die::getAttribute(_local, DW_AT_const_value, attribute);
	if (rtn == DW_DLV_ERROR) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	else if (rtn == DW_DLV_OK) {
		Dwarf_Error error;
		Dwarf_Half attributeFormat;
		rtn = dwarf_whatform(attribute.getPointer(), &attributeFormat, &error);
		if (rtn == DW_DLV_ERROR) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		else if (rtn == DW_DLV_NO_ENTRY) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		switch (attributeFormat) {
			case DW_FORM_block1:
			case DW_FORM_block2:
			case DW_FORM_block4: {
				dwarf::RaiiPointer<Dwarf_Block *> block(_debug);
				rtn = dwarf_formblock(attribute.getPointer(), &block.getPointer(), &error);
				if (rtn == DW_DLV_ERROR) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				else if (rtn == DW_DLV_NO_ENTRY) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				dwarf::LocationCursorByAddress locationCursor(block.getPointer()->bl_data);
				if (!print(_debug, type.getPointer(), locationCursor, _level)) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				printf("\n");
				return true;
			}
			case DW_FORM_data1:
			case DW_FORM_data2:
			case DW_FORM_data4:
			case DW_FORM_data8:
			case DW_FORM_sdata: {
				Dwarf_Signed s;
				rtn = dwarf_formsdata(attribute.getPointer(), &s, &error);
				if (rtn == DW_DLV_ERROR) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				else if (rtn == DW_DLV_NO_ENTRY) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				dwarf::LocationCursorByAddress locationCursor(&s);
				if (!print(_debug, type.getPointer(), locationCursor, _level)) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				printf("\n");
				return true;
			}
			case DW_FORM_udata: {
				Dwarf_Unsigned u;
				rtn = dwarf_formudata(attribute.getPointer(), &u, &error);
				if (rtn == DW_DLV_ERROR) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				else if (rtn == DW_DLV_NO_ENTRY) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				dwarf::LocationCursorByAddress locationCursor(&u);
				if (!print(_debug, type.getPointer(), locationCursor, _level)) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				printf("\n");
				return true;
			}
			default: {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
		}
	}
	printf("$.oo\n");
	return true;
}

bool SelfDebug::printInheritance(Dwarf_Debug _debug, Dwarf_Die _inheritance, const void *_object, size_t _level) const {
	dwarf::RaiiPointer<Dwarf_Die> type(_debug);
	int rtn = dwarf::Die::getType(_debug, _inheritance, type);
	if (rtn == DW_DLV_ERROR) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	else if (rtn == DW_DLV_NO_ENTRY) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	dwarf::RaiiPointer<char *> name(_debug);
	rtn = dwarf::Die::getName(type.getPointer(), name);
	if (rtn == DW_DLV_ERROR) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	else if (rtn == DW_DLV_NO_ENTRY) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	printf("%s\"Inherit from %s\": ", getTabs(_level), name.getPointer());
	void *address;
	rtn = dwarf::Die::getMemberAddress(_debug, _inheritance, _object, address);
	if (rtn == DW_DLV_ERROR) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	else if (rtn == DW_DLV_NO_ENTRY) {
		printf("$.oo\n");
		return true;
	}
	dwarf::LocationCursorByAddress locationCursor(address);
	if (!print(_debug, type.getPointer(), locationCursor, _level)) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	printf("\n");
	return true;
}

bool SelfDebug::printMember(Dwarf_Debug _debug, Dwarf_Die _member, const void *_object, size_t _level) const {
	dwarf::RaiiPointer<char *> name(_debug);
	int rtn = dwarf::Die::getName(_member, name);
	if (rtn == DW_DLV_ERROR) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	else if (rtn == DW_DLV_NO_ENTRY) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	printf("%s%s: ", getTabs(_level), name.getPointer());
	void *address;
	rtn = dwarf::Die::getMemberAddress(_debug, _member, _object, address);
	if (rtn == DW_DLV_ERROR) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	else if (rtn == DW_DLV_NO_ENTRY) {
		printf("$.oo\n");
		return true;
	}
	dwarf::RaiiPointer<Dwarf_Die> type(_debug);
	rtn = dwarf::Die::getType(_debug, _member, type);
	if (rtn == DW_DLV_ERROR) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	else if (rtn == DW_DLV_NO_ENTRY) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	dwarf::RaiiPointer<Dwarf_Attribute> attribute(_debug);
	rtn = dwarf::Die::getAttribute(_member, DW_AT_bit_size, attribute);
	if (rtn == DW_DLV_ERROR) {
		fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
		return false;
	}
	else if (rtn == DW_DLV_NO_ENTRY) {
		dwarf::LocationCursorByAddress locationCursor(address);
		if (!print(_debug, type.getPointer(), locationCursor, _level)) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
	}
	else {
		Dwarf_Error error;
		Dwarf_Unsigned bitSize;
		rtn = dwarf::Die::getBitSize(attribute.getPointer(), bitSize);
		if (rtn == DW_DLV_ERROR) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		else if (rtn == DW_DLV_NO_ENTRY) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		Dwarf_Unsigned bitOffset;
		rtn = dwarf::Die::getBitOffset(_debug, _member, bitOffset);
		if (rtn == DW_DLV_ERROR) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		else if (rtn == DW_DLV_NO_ENTRY) {
			fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
			return false;
		}
		while (true) {
			Dwarf_Half tag;
			rtn = dwarf::Die::getTag(type.getPointer(), tag);
			if (rtn == DW_DLV_ERROR) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			else if (rtn == DW_DLV_NO_ENTRY) {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
			if (tag == DW_TAG_typedef) {
				continue;
			}
			else if (tag == DW_TAG_enumeration_type) {
				Dwarf_Unsigned byteSize;
				rtn = dwarf_bytesize(type.getPointer(), &byteSize, &error);
				if (rtn == DW_DLV_ERROR) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				else if (rtn == DW_DLV_NO_ENTRY) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				if (byteSize == sizeof(int8_t)) {
					int8_t value = bitFieldToSigned<int8_t>(address, bitSize, bitOffset);
					dwarf::LocationCursorByAddress locationCursor(&value);
					if (!print(_debug, type.getPointer(), locationCursor, _level)) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					break;
				}
				else if (byteSize == sizeof(int16_t)) {
					int16_t value = bitFieldToSigned<int16_t>(address, bitSize, bitOffset);
					dwarf::LocationCursorByAddress locationCursor(&value);
					if (!print(_debug, type.getPointer(), locationCursor, _level)) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					break;
				}
				else if (byteSize == sizeof(int32_t)) {
					int32_t value = bitFieldToSigned<int32_t>(address, bitSize, bitOffset);
					dwarf::LocationCursorByAddress locationCursor(&value);
					if (!print(_debug, type.getPointer(), locationCursor, _level)) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					break;
				}
				else if (byteSize == sizeof(int64_t)) {
					int64_t value = bitFieldToSigned<int64_t>(address, bitSize, bitOffset);
					dwarf::LocationCursorByAddress locationCursor(&value);
					if (!print(_debug, type.getPointer(), locationCursor, _level)) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					break;
				}
				else {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				break;
			}
			else if (tag == DW_TAG_base_type) {
				Dwarf_Unsigned encoding;
				rtn = dwarf::Die::getEncoding(_debug, type.getPointer(), encoding);
				if (rtn == DW_DLV_ERROR) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				else if (rtn == DW_DLV_NO_ENTRY) {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
				if (encoding == DW_ATE_boolean) {
					bool value = bitFieldToUnsigned<bool>(address, bitSize, bitOffset);
					dwarf::LocationCursorByAddress locationCursor(&value);
					if (!print(_debug, type.getPointer(), locationCursor, _level)) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					break;
				}
				else if (encoding == DW_ATE_signed) {
					Dwarf_Unsigned byteSize;
					rtn = dwarf_bytesize(type.getPointer(), &byteSize, &error);
					if (rtn == DW_DLV_ERROR) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					else if (rtn == DW_DLV_NO_ENTRY) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					if (byteSize == sizeof(int8_t)) {
						int8_t value = bitFieldToSigned<int8_t>(address, bitSize, bitOffset);
						dwarf::LocationCursorByAddress locationCursor(&value);
						if (!print(_debug, type.getPointer(), locationCursor, _level)) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						break;
					}
					else if (byteSize == sizeof(int16_t)) {
						int16_t value = bitFieldToSigned<int16_t>(address, bitSize, bitOffset);
						dwarf::LocationCursorByAddress locationCursor(&value);
						if (!print(_debug, type.getPointer(), locationCursor, _level)) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						break;
					}
					else if (byteSize == sizeof(int32_t)) {
						int32_t value = bitFieldToSigned<int32_t>(address, bitSize, bitOffset);
						dwarf::LocationCursorByAddress locationCursor(&value);
						if (!print(_debug, type.getPointer(), locationCursor, _level)) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						break;
					}
					else if (byteSize == sizeof(int64_t)) {
						int64_t value = bitFieldToSigned<int64_t>(address, bitSize, bitOffset);
						dwarf::LocationCursorByAddress locationCursor(&value);
						if (!print(_debug, type.getPointer(), locationCursor, _level)) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						break;
					}
					else {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
				}
				else if (encoding == DW_ATE_signed_char) {
					signed char value = bitFieldToSigned<signed char>(address, bitSize, bitOffset);
					dwarf::LocationCursorByAddress locationCursor(&value);
					if (!print(_debug, type.getPointer(), locationCursor, _level)) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					break;
				}
				else if (encoding == DW_ATE_unsigned) {
					Dwarf_Unsigned byteSize;
					rtn = dwarf_bytesize(type.getPointer(), &byteSize, &error);
					if (rtn == DW_DLV_ERROR) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					else if (rtn == DW_DLV_NO_ENTRY) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					if (byteSize == sizeof(uint8_t)) {
						uint8_t value = bitFieldToUnsigned<uint8_t>(address, bitSize, bitOffset);
						dwarf::LocationCursorByAddress locationCursor(&value);
						if (!print(_debug, type.getPointer(), locationCursor, _level)) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						break;
					}
					else if (byteSize == sizeof(uint16_t)) {
						uint16_t value = bitFieldToUnsigned<uint16_t>(address, bitSize, bitOffset);
						dwarf::LocationCursorByAddress locationCursor(&value);
						if (!print(_debug, type.getPointer(), locationCursor, _level)) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						break;
					}
					else if (byteSize == sizeof(uint32_t)) {
						uint32_t value = bitFieldToUnsigned<uint32_t>(address, bitSize, bitOffset);
						dwarf::LocationCursorByAddress locationCursor(&value);
						if (!print(_debug, type.getPointer(), locationCursor, _level)) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						break;
					}
					else if (byteSize == sizeof(uint64_t)) {
						uint64_t value = bitFieldToUnsigned<uint64_t>(address, bitSize, bitOffset);
						dwarf::LocationCursorByAddress locationCursor(&value);
						if (!print(_debug, type.getPointer(), locationCursor, _level)) {
							fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
							return false;
						}
						break;
					}
					else {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
				}
				else if (encoding == DW_ATE_unsigned_char) {
					unsigned char value = bitFieldToUnsigned<unsigned char>(address, bitSize, bitOffset);
					dwarf::LocationCursorByAddress locationCursor(&value);
					if (!print(_debug, type.getPointer(), locationCursor, _level)) {
						fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
						return false;
					}
					break;
				}
				else {
					fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
					return false;
				}
			}
			else {
				fprintf(stderr, "[ERR] (%s, %d) %s\n", __FILE__, __LINE__, __FUNCTION__);
				return false;
			}
		}
	}
	printf("\n");
	return true;
}

}
}
